#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "automata.h"
#include "util.h"
#include "testInputs.h"
#include "longInt.h"
#define DEBUG

#ifdef DEBUG
    #define DEBUGM  printf
#else
    #define DEBUGM  //
#endif

#define MAX_REGEXP_SIZE     4096
#define MAX_CHAIN_SIZE      4096



/*
*   Writes .out file containing Minimal DFA
*/
void writeFile(char *fname, t_table * t);


void addInputChain(t_input *t, char *chain);
void readFile(char *fname, char *exp, t_input *in);



int main(int argc, char *argv[])
{
    t_table *t;
    t_input input;
    char expression[MAX_REGEXP_SIZE];
    char fileName[256]; //= "regexp3.in";
    int i;
       
    if(argc!=2)
        error(1, "\nUse: regexp filename.in\n");


    SetLog("logfile.txt");

    strncpy(fileName, argv[1], 255);

    LogMsg("Attempting to open and parse file \"%s\"... ", fileName);


    readFile(fileName, expression, &input);

//    system("pause");
//    exit(0);



    LogMsg("OK\nSetting regular expression...");
    SetRegExp(expression);

    LogMsg("OK\nTranslating into an automaton...");
    t = TranslateRegExp();

    LogTable(t, "AFTER TRANSLATION");

    LogMsg("OK\nRemoving lambda transitions...");
    removeLambdaTrans(t);

    LogTable(t, "AFTER LAMBDA REMOTION");

    LogMsg("OK\nDeterminizing...");
    nfaToDfa(t);

    LogTable(t, "AFTER DETERMINIZATION");

    LogMsg("OK\nMinimizing...");
    MinimizeDFA(t);

    LogTable(t, "AFTER MINIMIZATION");

    LogMsg("OK\nSetting input chains...");
    t->input = input;

    LogMsg("OK\nTesting input chains...");
    testInput(t);

    i = strlen(fileName) - 2;
    strcpy(fileName + i, "out");
    LogMsg("OK\nWriting output file \"%s\"...", fileName);
    writeFile(fileName, t);

    LogMsg("OK\n\nDone.\n");
    
    system("pause");
    return 0;
}

void
writeFile(char *fname, t_table * t)
{
    int i, j, st, alphabetDim;
    FILE *f;
    
    if ((f = fopen(fname, "w")) == NULL)
        error(1, "Could not open output file\n");
    
    alphabetDim = strlen(t->alphabet);
    
    //Print Alphabet
    fprintf(f,"%s\n",t->alphabet);

    //Print number of states
    fprintf(f,"%d\n",t->states.dim);

    //Print initial state
    fprintf(f,"%d\n",t->iniState);

    //Print final states
    if (t->finalStates.dim > 0)
    {
        for(i=0;i<t->finalStates.dim-1;i++)
            fprintf(f,"%d ",getStateIndex(t,t->finalStates.vec[i]));
        fprintf(f,"%d\n",getStateIndex(t,t->finalStates.vec[i]));
    }
    else fprintf(f, "\n"); 
        

    //Print transitions
    for(i=0;i<t->transitions.fils;i++)
        for(j=0;j<alphabetDim;j++)
            if ((st = t->transitions.data[i][j]) != -1)
                fprintf(f,"%d %d %c\n",i, st,t->alphabet[j]);
                
    fprintf(f,"\n");
    for(i=0;i<t->input.dim-1;i++)
        fprintf(f,"%s\n",t->input.chains[i]);
    fprintf(f,"%s",t->input.chains[i]);
}


int
getline(char * line, int max, FILE * f)
{
    int cant;

    if(fgets(line, max, f)==NULL)
        return -1;

    return RemoveReturnWLM(line);
}


void addInputChain(t_input *in, char *chain)
{
    // Para evitar un bug inexplicable, se reserva espacio inicialmente
    // para una cantidad grande de cadenas, evitando un realloc.
    if (in->dim == 0)
        if ((in->chains = malloc(1024 * sizeof(char*))) == NULL)
            error(1, "Malloc failed!\n");

    in->dim++;

    in->chains[in->dim-1] = malloc(sizeof(char) * (strlen(chain)+1));
    
    if (in->chains[in->dim-1] == NULL)
        error(1, "Malloc failed!!!\n");
    
    strcpy(in->chains[in->dim-1], chain);

    return;
}

void readFile(char *fname, char *exp, t_input *in)
{
    FILE *f;
    int i;
    
    char chain[MAX_CHAIN_SIZE];
    
    
    if ((f = fopen(fname, "r")) == NULL)
        error(1, "Could not open input file.\n");

        
    getline(exp, MAX_REGEXP_SIZE, f);

//    system("pause");
    in->dim = 0;
    in->chains = 0;

    while(getline(chain, MAX_CHAIN_SIZE, f) >= 0)
        addInputChain(in, chain);

/*
        addInputChain(in, "1");
        addInputChain(in, "2");
        addInputChain(in, "3");
        addInputChain(in, "4");
        addInputChain(in, "5");
        addInputChain(in, "6");
        addInputChain(in, "7");
        addInputChain(in, "8");
        addInputChain(in, "9");
        addInputChain(in, "10");
        addInputChain(in, "11");
    printf("Cadenas (%d):\n", in->dim);
    for (i = 0; i < in->dim; i++)
    {
        printf("In[%d] (%p) : ", i, in->chains[i]);
        printf("\"%s\"\n", in->chains[i]);
    }
*/

    close(f);
    
    return;
}




